package com.ruoyi.collect.engine.parser;

import com.ruoyi.collect.engine.client.MacCmsResponse;
import com.ruoyi.collect.engine.client.MacCmsResponse.PageInfo;
import com.ruoyi.collect.engine.client.MacCmsResponse.TypeInfo;
import com.ruoyi.collect.engine.client.MacCmsResponse.VodInfo;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * XML format resource parser
 * Parse XML format MacCMS API response with CDATA support
 *
 * @author ruoyi
 * @date 2025-11-07
 */
@Component
public class XmlResourceParser implements IResourceParser {

    private static final Logger log = LoggerFactory.getLogger(XmlResourceParser.class);

    @Override
    public boolean support(String content) {
        if (content == null || content.isEmpty()) {
            log.debug("XML parser: content is null or empty");
            return false;
        }

        String trimmedContent = content.trim();
        boolean isXml = trimmedContent.startsWith("<?xml") || trimmedContent.startsWith("<");

        log.debug("XML parser support check: starts with '<?xml': {}, starts with '<': {}, result: {}",
            trimmedContent.startsWith("<?xml"), trimmedContent.startsWith("<"), isXml);

        if (isXml && trimmedContent.length() > 20) {
            log.debug("XML parser: first 50 chars: {}", trimmedContent.substring(0, Math.min(50, trimmedContent.length())));
        }

        return isXml;
    }

    @Override
    public MacCmsResponse parse(String content) {
        try {
            log.debug("Starting to parse XML content, length: {}", content.length());

            // Process CDATA sections
            content = processCDATA(content);

            // Parse XML
            Document document = DocumentHelper.parseText(content);
            Element root = document.getRootElement();

            MacCmsResponse response = new MacCmsResponse();

            // Parse list element
            Element listElement = root.element("list");
            if (listElement != null) {
                response.setPage(parsePageInfo(listElement));
                response.setList(parseVodList(listElement));
            }

            // Parse class element for types
            Element classElement = root.element("class");
            if (classElement != null) {
                response.setTypeList(parseTypeList(classElement));
            }

            log.info("Successfully parsed XML content, got {} vod items",
                response.getList() != null ? response.getList().size() : 0);

            return response;

        } catch (Exception e) {
            log.error("XML parse failed: {}", e.getMessage());
            log.debug("XML content first 500 chars: {}", content.length() > 500 ? content.substring(0, 500) : content);
            throw new RuntimeException("XML parse failed: " + e.getMessage(), e);
        }
    }

    /**
     * Process CDATA sections
     */
    private String processCDATA(String xml) {
        // Remove CDATA markers to simplify parsing
        xml = xml.replaceAll("<!\\[CDATA\\[", "");
        xml = xml.replaceAll("\\]\\]>", "");

        // Escape special characters
        xml = xml.replaceAll("&(?![a-zA-Z]+;)", "&amp;");

        return xml;
    }

    /**
     * Parse page info
     */
    private PageInfo parsePageInfo(Element listElement) {
        PageInfo pageInfo = new PageInfo();

        String page = listElement.attributeValue("page");
        String pagecount = listElement.attributeValue("pagecount");
        String pagesize = listElement.attributeValue("pagesize");
        String recordcount = listElement.attributeValue("recordcount");

        if (page != null) pageInfo.setPage(Integer.parseInt(page));
        if (pagecount != null) pageInfo.setPagecount(Integer.parseInt(pagecount));
        if (pagesize != null) pageInfo.setPagesize(Integer.parseInt(pagesize));
        if (recordcount != null) pageInfo.setRecordcount(Integer.parseInt(recordcount));

        return pageInfo;
    }

    /**
     * Parse vod list
     */
    private List<VodInfo> parseVodList(Element listElement) {
        List<VodInfo> vodList = new ArrayList<>();

        List<Element> videos = listElement.elements("video");
        for (Element video : videos) {
            VodInfo vod = new VodInfo();

            // Basic info
            Element idEl = video.element("id");
            if (idEl != null) vod.setVodId(idEl.getText());

            Element nameEl = video.element("name");
            if (nameEl != null) vod.setVodName(nameEl.getText());

            Element tidEl = video.element("tid");
            if (tidEl != null) vod.setTypeId(tidEl.getText());

            Element typeEl = video.element("type");
            if (typeEl != null) {
                // Store type name in VodInfo, we'll handle this during data transformation
                // For now just store in remarks or skip
                // vod.setVodClass(typeEl.getText()); // This field doesn't exist
            }

            // Image
            Element picEl = video.element("pic");
            if (picEl != null) vod.setVodPic(picEl.getText());

            // Additional info
            Element areaEl = video.element("area");
            if (areaEl != null) vod.setVodArea(areaEl.getText());

            Element langEl = video.element("lang");
            if (langEl != null) vod.setVodLang(langEl.getText());

            Element yearEl = video.element("year");
            if (yearEl != null) vod.setVodYear(yearEl.getText());

            // People
            Element actorEl = video.element("actor");
            if (actorEl != null) vod.setVodActor(actorEl.getText());

            Element directorEl = video.element("director");
            if (directorEl != null) vod.setVodDirector(directorEl.getText());

            // Content
            Element desEl = video.element("des");
            if (desEl != null) vod.setVodContent(desEl.getText());

            Element noteEl = video.element("note");
            if (noteEl != null) vod.setVodRemarks(noteEl.getText());

            // Episode info
            Element serialEl = video.element("serial");
            if (serialEl != null) vod.setVodSerial(serialEl.getText());

            Element stateEl = video.element("state");
            if (stateEl != null) vod.setVodTotal(stateEl.getText());

            // Play info (in dl/dd structure)
            Element dlEl = video.element("dl");
            if (dlEl != null) {
                StringBuilder playFrom = new StringBuilder();
                StringBuilder playUrl = new StringBuilder();

                List<Element> ddList = dlEl.elements("dd");
                for (int i = 0; i < ddList.size(); i++) {
                    Element dd = ddList.get(i);
                    String flag = dd.attributeValue("flag");
                    String urls = dd.getText();

                    if (i > 0) {
                        playFrom.append("$$$");
                        playUrl.append("$$$");
                    }
                    playFrom.append(flag);
                    playUrl.append(urls);
                }

                vod.setVodPlayFrom(playFrom.toString());
                vod.setVodPlayUrl(playUrl.toString());
            }

            vodList.add(vod);
        }

        return vodList;
    }

    /**
     * Parse type list
     */
    private List<TypeInfo> parseTypeList(Element classElement) {
        List<TypeInfo> typeList = new ArrayList<>();

        List<Element> types = classElement.elements("ty");
        for (Element type : types) {
            TypeInfo typeInfo = new TypeInfo();

            String id = type.attributeValue("id");
            if (id != null) typeInfo.setTypeId(id);

            String typeName = type.getText();
            if (typeName != null) typeInfo.setTypeName(typeName);

            typeList.add(typeInfo);
        }

        return typeList;
    }

    @Override
    public String getType() {
        return "XML";
    }
}